// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package log

import (
	"context"
	"fmt"
	"gitee.com/go-wares/log/base"
	"gitee.com/go-wares/log/conf"
	"gitee.com/go-wares/log/tracer"
	"net/http"
)

// Span
// is an interface for call chain span.
type Span = base.Span

// Close
// logging and span reporter. This should be called in main function
// before exited.
//
//	  func main(){
//		    defer log.Close()
//	     ...
//	  }
func Close() {
	Manager.StopAndWait()
}

// Config
// returns the configuration of log.
//
//	conf := log.Config()
//	conf := log.Manager.Config()
func Config() *conf.Config {
	return Manager.Config()
}

// ContextHeaders
// creates the headers map from a context.
func ContextHeaders(ctx context.Context) map[string]string {
	if ctx != nil {
		if v, ok := ctx.Value(base.TracingOnContext).(*base.Tracing); ok {
			c := conf.Get()

			return map[string]string{
				c.OpentracingTraceId:      v.TraceId.String(),
				c.OpentracingSpanId:       v.SpanId.String(),
				c.OpentracingSpanPosition: fmt.Sprintf(`%d`, v.SpanPosition),
			}
		}
	}
	return nil
}

// NewContext
// creates a new context with a tracing component.
func NewContext(ctx ...context.Context) context.Context {
	if len(ctx) > 0 && ctx[0] != nil {
		if v, ok := ctx[0].Value(base.TracingOnContext).(*base.Tracing); ok {
			return context.WithValue(ctx[0], base.TracingOnContext, v.Child())
		}
		return context.WithValue(ctx[0], base.TracingOnContext, base.NewTracing())
	}
	return context.WithValue(tracer.RootCtx, base.TracingOnContext, base.NewTracing())
}

// NewSpan
// creates a new span component.
func NewSpan(format string, args ...any) Span {
	return tracer.NewSpan(Manager, format, args...)
}

// NewSpanWithContext
// creates a new span component.
func NewSpanWithContext(ctx context.Context, format string, args ...any) Span {
	return tracer.NewSpanWithContext(ctx, Manager, format, args...)
}

func NewSpanWithHeader(header map[string]any, format string, args ...any) Span {
	return tracer.NewSpanWithHeaders(Manager, header, format, args...)
}

// NewSpanWithRequest
// creates a new span component with given request of a http request.
func NewSpanWithRequest(req *http.Request) Span {
	return tracer.NewSpanWithRequest(Manager, req)
}
